home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / IFC_112 / netscape / application / View.java < prev    next >
Encoding:
Text File  |  1999-05-28  |  81.7 KB  |  2,474 lines  |  [TEXT/CWIE]

  1. // View.java
  2. // By Ned Etcode
  3. // Copyright 1995, 1996, 1997 Netscape Communications Corp. All rights reserved.
  4.  
  5. package netscape.application;
  6.  
  7. import netscape.util.*;
  8.  
  9.  
  10. /** A View is a rectangular entity capable of drawing on the screen and
  11.   * receiving Events. All objects that need to perform one or both of these
  12.   * functions (Buttons, Sliders, Windows) are View subclasses. Views are
  13.   * arranged in a tree-like hierarchy, with each View having zero or more
  14.   * subviews, called descendants. Before a View can draw or receive Events,
  15.   * it must be placed within this hierarchy, through some form of the
  16.   * <b>addSubview()</b> method. A RootView instance sits at the top
  17.   * of the hierarchy, and all other Views descend from it.<p>
  18.   * Each View has an origin and size, defined by the View's <B>bounds</B>
  19.   * instance variable. A View's origin is defined in its superview's
  20.   * coordinates. A RootView has an origin of (0, 0) and a size as
  21.   * defined by the HTML document that invoked the Application, or
  22.   * ExternalWindow containing the RootView. The
  23.   * coordinate system's positive Y-axis points down. For example, a subview
  24.   * of the RootView with its origin 50 pixels below and 100 pixels
  25.   * to the right of the RootView's origin has an origin of (100, 50).<p>
  26.   * A View subclass that wants to draw must override the <b>drawView()</b>
  27.   * method. The Graphics object passed into this method has its clip rect set
  28.   * such that the View cannot accidentally draw outside of its bounds. The
  29.   * Graphics object's coordinate system has been altered, allowing the View to
  30.   * draw using its own relative coordinate system.  Using the subview in the
  31.   * above example, the following code draws a red square at the View's origin:
  32.   * <PRE>
  33.   *     g.setColor(Color.red);
  34.   *     g.fillRect(0, 0, 20, 20);
  35.   * </PRE> <p>
  36.   * While Views encompass rectangular regions within the View hierarchy, they
  37.   * can simulate non-rectangular entities through the notion of transparency.
  38.   * Overriding the method <b>isTransparent()</b> to return <b>true</b> tells
  39.   * the IFC's drawing machinery that at
  40.   * least some portion of the View's drawing area is not redrawn by its
  41.   * <b>drawView()</b> method. Whenever the View needs to be redrawn, the
  42.   * drawing machinery assures that the transparent View's superview, or
  43.   * some other opaque ancestor, redraws the region behind the transparent
  44.   * View before calling the transparent View's <b>drawView()</b> method.
  45.   * In general, you do not need to know the exact mechanism - just
  46.   * have your View's <b>isTransparent()</b> method return <b>true</b> and
  47.   * everything else happens as it
  48.   * should. By default, <b>isTransparent()</b> returns <b>true</b>, so if
  49.   * your View is not transparent, you should override this method to return
  50.   * <b>false</b>.<p>
  51.   * You can also make a View "buffered," meaning that
  52.   * all drawing performed by the View goes first to an offscreen buffer
  53.   * and then onscreen. With a buffered View, you get flicker-free drawing,
  54.   * but at the cost of slightly reduced performance.<p>
  55.   * To force a View to draw itself,
  56.   * you call the View's <b>draw()</b> method. All drawing is synchronous,
  57.   * meaning that a <b>draw()</b> request is peformed
  58.   * immediately (<b>draw()</b> does not return until all drawing has
  59.   * completed).<p>
  60.   * Views interested in processing mouse events must override one of the mouse
  61.   * event methods and take appropriate action.  Event locations are presented
  62.   * in terms of the View's coordinate system.<p>
  63.   * @see #addSubview
  64.   * @see #removeFromSuperview
  65.   * @see #draw
  66.   * @see #drawView
  67.   * @see #isTransparent
  68.   * @see #setBuffered
  69.   * @note 1.0 added support for asian input managers.
  70.   * @note 1.0 It is now possible to call setFocusedView() on a view that's not
  71.   *           connected into the view hierarchy. When the view or it's parent
  72.   *           get connected, it gets the focus. If more than one view
  73.   *           request the focus, the last view added to view hierarchy get
  74.   *           the focus.
  75.   * @note 1.0 Added keyboard UI api.
  76.   * @note 1.0 added CENTER as primative layout type
  77.   * @note 1.0 archiving changed
  78.   * @note 1.1.1 added keyTyped.
  79.   */
  80.  
  81. public class View implements Codable {
  82.     View                _superview;
  83.     Size                _minSize;
  84.     Bitmap              drawingBuffer;
  85.     private Vector      subviews;
  86.     private Vector      kbdOrder;
  87.     LayoutManager       layoutManager;
  88.     Hashtable           _keyboardBindings;
  89.     /** The View's bounding rectangle, in its superview's coordinate
  90.       * system. The <b>bounds</b> field should only be used for reading.
  91.       * You should never modify this field directly. To move or resize a
  92.       * View call <b>setBounds()</b>.
  93.       * @see #setBounds
  94.       * @see #bounds()
  95.       * @see #localBounds
  96.       */
  97.     public Rect         bounds = new Rect();
  98.  
  99.     Rect                dirtyRect;
  100.     byte                resizeInstr = (byte)DEFAULT_RESIZE_INSTR;
  101.     int                 drawingDisabled = 0;
  102.     boolean             autoResizeSubviews = true,
  103.                         buffered;
  104.     boolean             drawingBufferValid;
  105.     boolean             drawingBufferIsBitCache;
  106.     boolean             isDirty;
  107.     boolean             needFocus;
  108.     boolean             focusPaused;
  109.     boolean             wantsKeyboardArrow;
  110.  
  111.     /** Horizontal resize instruction.    */
  112.     public final static int     RIGHT_MARGIN_CAN_CHANGE = 0;
  113.     /** Horizontal resize instruction.    */
  114.     public final static int     LEFT_MARGIN_CAN_CHANGE = 1;
  115.     /** Horizontal resize instruction.    */
  116.     public final static int     WIDTH_CAN_CHANGE = 2;
  117.     /** Horizontal resize instruction.
  118.       *
  119.       */
  120.     public final static int     CENTER_HORIZ = 32;
  121.  
  122.     /** Vertical resize instruction. */
  123.     public final static int     BOTTOM_MARGIN_CAN_CHANGE = 4;
  124.     /** Vertical resize instruction. */
  125.     public final static int     TOP_MARGIN_CAN_CHANGE = 8;
  126.     /** Vertical resize instruction. */
  127.     public final static int     HEIGHT_CAN_CHANGE = 16;
  128.     /** Vertical resize instruction.
  129.       *
  130.       */
  131.     public final static int     CENTER_VERT = 64;
  132.  
  133.     private final static int    DEFAULT_RESIZE_INSTR =
  134.                                         RIGHT_MARGIN_CAN_CHANGE |
  135.                                         BOTTOM_MARGIN_CAN_CHANGE;
  136.     private final static int    VERT_MASK = BOTTOM_MARGIN_CAN_CHANGE |
  137.                                             TOP_MARGIN_CAN_CHANGE |
  138.                                             HEIGHT_CAN_CHANGE |
  139.                                             CENTER_VERT;
  140.     private final static int    HORZ_MASK = RIGHT_MARGIN_CAN_CHANGE |
  141.                                             LEFT_MARGIN_CAN_CHANGE |
  142.                                             WIDTH_CAN_CHANGE |
  143.                                             CENTER_HORIZ;
  144.  
  145.     final static String         MINSIZE_KEY = "minSize",
  146.                                 BOUNDS_KEY = "bounds",
  147.                                 SUBVIEWS_KEY = "subviews",
  148.                                 RESIZE_KEY = "resizeInstr",
  149.                                 DRAWINGDISABLED_KEY = "drawingDisabled",
  150.                                 AUTORESIZE_KEY = "autoResizeSubviews",
  151.                                 BUFFERED_KEY = "buffered",
  152.                                 LAYOUTMANAGER_KEY = "layoutManager",
  153.                                 KEYBOARD_BINDINGS_KEY = "keyboardBindings";
  154.  
  155.     private final static String  KBD_COMMAND_KEY = "kbdCmd";
  156.     private final static String  KBD_WHEN        = "when";
  157.     private final static String  KBD_DATA_KEY = "kbdData";
  158.  
  159.     static final int  DEFAULT_CURSOR = -1;
  160.     /** Arrow cursor. */
  161.     public static final int  ARROW_CURSOR = java.awt.Frame.DEFAULT_CURSOR;
  162.     /** Crosshair cursor. */
  163.     public static final int  CROSSHAIR_CURSOR =
  164.                                             java.awt.Frame.CROSSHAIR_CURSOR;
  165.     /** Text cursor. */
  166.     public static final int  TEXT_CURSOR = java.awt.Frame.TEXT_CURSOR;
  167.     /** Wait cursor. */
  168.     public static final int  WAIT_CURSOR = java.awt.Frame.WAIT_CURSOR;
  169.     /** Southwest resize cursor. */
  170.     public static final int  SW_RESIZE_CURSOR =
  171.                                             java.awt.Frame.SW_RESIZE_CURSOR;
  172.     /** Southeast resize cursor. */
  173.     public static final int  SE_RESIZE_CURSOR =
  174.                                             java.awt.Frame.SE_RESIZE_CURSOR;
  175.     /** Northwest resize cursor. */
  176.     public static final int  NW_RESIZE_CURSOR =
  177.                                             java.awt.Frame.NW_RESIZE_CURSOR;
  178.     /** Northeast resize cursor. */
  179.     public static final int  NE_RESIZE_CURSOR =
  180.                                             java.awt.Frame.NE_RESIZE_CURSOR;
  181.     /** North resize cursor. */
  182.     public static final int  N_RESIZE_CURSOR = java.awt.Frame.N_RESIZE_CURSOR;
  183.     /** South resize cursor. */
  184.     public static final int  S_RESIZE_CURSOR = java.awt.Frame.S_RESIZE_CURSOR;
  185.     /** West resize cursor. */
  186.     public static final int  W_RESIZE_CURSOR = java.awt.Frame.W_RESIZE_CURSOR;
  187.     /** East resize cursor. */
  188.     public static final int  E_RESIZE_CURSOR = java.awt.Frame.E_RESIZE_CURSOR;
  189.     /** Hand cursor. */
  190.     public static final int  HAND_CURSOR = java.awt.Frame.HAND_CURSOR;
  191.     /** Move cursor. */
  192.     public static final int  MOVE_CURSOR = java.awt.Frame.MOVE_CURSOR;
  193.  
  194.  
  195.     /** Flags to descrive when to receive keyboard UI commands **/
  196.     /** The view should receive the command only the selected
  197.       *
  198.       */
  199.     public static final int WHEN_SELECTED = 0;
  200.  
  201.     /** The view should receive the command only when it is in the main window
  202.       * The command is also sent when the view is selected.
  203.       *
  204.       **/
  205.     public static final int WHEN_IN_MAIN_WINDOW = 1;
  206.  
  207.     /** Always send the command. You should be careful with this option since
  208.       * the command will always be sent, even when a modal session is running.
  209.       * The command is also sent when the component is in the main window or is
  210.       * selected.
  211.       *
  212.       */
  213.     public static final int ALWAYS = 2;
  214.  
  215.  
  216.     /* constructors */
  217.  
  218.     /** Constructs a View with origin (<b>0</b>, <b>0</b>) and zero width
  219.       * and height.
  220.       */
  221.     public View() {
  222.         this(0, 0, 0, 0);
  223.     }
  224.  
  225.     /** Constructs a View with bounds <B>rect</B>.
  226.       */
  227.     public View(Rect rect) {
  228.         this(rect.x, rect.y, rect.width, rect.height);
  229.     }
  230.  
  231.     /** Constructs a View with bounds
  232.       * (<B>x</B>, <B>y</B>, <B>width</B>, <B>height</B>).
  233.       */
  234.     public View(int x, int y, int width, int height) {
  235.         super();
  236.         _setBounds(x, y, width, height);
  237.  
  238.         // init() ALERT!  It would be great if this were the case...
  239.         // setBounds(x, y, width, height);
  240.     }
  241.  
  242.     void _setBounds(int x, int y, int width, int height) {
  243.         bounds.setBounds(x, y, width, height);
  244.     }
  245.  
  246.     /* attributes */
  247.  
  248.     /** This is a hook we use to avoid making the subviews Vector until
  249.       * needed. There is very little code in IFC which blindly walks down
  250.       * the View hierarchy. Where such code occurs it should call this
  251.       * method to get the subviewCount. Calling subviews().count() will
  252.       * create a Vector even if there are no subviews.
  253.       */
  254.     int subviewCount() {
  255.         if (subviews == null)
  256.             return 0;
  257.  
  258.         return subviews.count();
  259.     }
  260.  
  261.     /** Returns the View's subviews. Do not modify the Vector's contents.
  262.       */
  263.     public Vector subviews() {
  264.         if (subviews == null)
  265.             subviews = new Vector();
  266.  
  267.         return subviews;
  268.     }
  269.  
  270.     /** Returns <b>subview</b>'s "peers," the Views in the same level in the
  271.       * View hierarchy.  "RadioButtons" call this method to locate all
  272.       * RadioButtons with the same superview.  This method returns the View's
  273.       * subviews, if <b>subview</b> is a subview of the View, an empty Vector
  274.       * otherwise.  Override this method to return a different list of peers.
  275.       * @private
  276.       */
  277.     public Vector peersForSubview(View subview) {
  278.         Vector          newVector;
  279.  
  280.         if (subviewCount() == 0 || !subviews().contains(subview)) {
  281.             return new Vector();
  282.         }
  283.  
  284.         newVector = new Vector();
  285.         newVector.addElementsIfAbsent(subviews);
  286.         return newVector;
  287.     }
  288.  
  289.     /** Returns <B>true</B> if the View is a descendant of or equals
  290.       * <B>aView</B>.
  291.       */
  292.     public boolean descendsFrom(View aView) {
  293.         if(aView == this)
  294.             return true;
  295.         if (_superview == null || aView == null) {
  296.             return false;
  297.         } else if (_superview == aView) {
  298.             return true;
  299.         }
  300.  
  301.         return _superview.descendsFrom(aView);
  302.     }
  303.  
  304.     /** Returns the View's InternalWindow, or <B>null</B> if a subview of
  305.       * the RootView.
  306.       */
  307.     public InternalWindow window() {
  308.         if (_superview == null) {
  309.             return null;
  310.         } else {
  311.             return _superview.window();
  312.         }
  313.     }
  314.  
  315.    /** Returns a newly-allocated copy of the View's bounding rectangle, which
  316.      * defines the View's size and position within its superview's coordinate
  317.      * system.
  318.      * @see #setBounds
  319.      * @see #moveBy
  320.      * @see #sizeBy
  321.      * @see #moveTo
  322.      * @see #sizeTo
  323.      * @see #localBounds
  324.      */
  325.     public Rect bounds() {
  326.         return new Rect(bounds);
  327.     }
  328.  
  329.     /** Returns the View's x location.
  330.       * @see #bounds()
  331.       */
  332.     public int x() {
  333.         return bounds.x;
  334.     }
  335.  
  336.     /** Returns the View's y location.
  337.       * @see #bounds()
  338.       */
  339.     public int y() {
  340.         return bounds.y;
  341.     }
  342.  
  343.     /** Returns the View's width.
  344.       * @see #bounds()
  345.       */
  346.     public int width() {
  347.         return bounds.width;
  348.     }
  349.  
  350.     /** Returns the View's height.
  351.       * @see #bounds()
  352.       */
  353.     public int height() {
  354.         return bounds.height;
  355.     }
  356.  
  357.     /** Returns the View's superview.
  358.       * @see #addSubview
  359.       * @see #removeFromSuperview
  360.       */
  361.     public View superview() {
  362.         return _superview;
  363.     }
  364.  
  365.    /** Sets the View's horizontal resize instruction, an integer value that
  366.      * represents the various ways in which a View can change its size in
  367.      * response to its superview's resizing. The default horizontal
  368.      * resize instruction is <B>RIGHT_MARGIN_CAN_CHANGE</B>, which keeps
  369.      * the View's left margin and width a fixed number of pixels.
  370.      */
  371.     public void setHorizResizeInstruction(int instruction) {
  372.         if (instruction != RIGHT_MARGIN_CAN_CHANGE
  373.             && instruction !=  LEFT_MARGIN_CAN_CHANGE
  374.             && instruction != WIDTH_CAN_CHANGE
  375.             && instruction != CENTER_HORIZ)
  376.             throw new IllegalArgumentException(
  377.                         "invalid horz resize instruction " + instruction);
  378.         resizeInstr &= VERT_MASK;       // Clear the HORZ bits by and'ed them
  379.                                         // with zeros
  380.         resizeInstr |= instruction;     // Set the bits properly
  381.     }
  382.  
  383.     /** Returns the View's horizontal resize instruction.
  384.       * @see #setHorizResizeInstruction
  385.       */
  386.     public int horizResizeInstruction() {
  387.          return resizeInstr & HORZ_MASK;
  388.     }
  389.  
  390.     /** Sets the View's vertical resize instruction, an integer value
  391.       * respresenting the various ways in which a View can change its size
  392.       * in response to its superview's resizing. The default vertical
  393.       * resize instruction is <B>BOTTOM_MARGIN_CAN_CHANGE</B>, which keeps
  394.       * the View's top margin and height a fixed number of pixels.
  395.       */
  396.     public void setVertResizeInstruction(int instruction) {
  397.         if (instruction != BOTTOM_MARGIN_CAN_CHANGE
  398.             && instruction !=  TOP_MARGIN_CAN_CHANGE
  399.             && instruction !=  HEIGHT_CAN_CHANGE
  400.             && instruction != CENTER_VERT)
  401.             throw new IllegalArgumentException(
  402.                             "invalid vert resize instruction " + instruction);
  403.         resizeInstr &= HORZ_MASK;       // Clear the VERT bits by and'ed them
  404.                                         // with zeros
  405.         resizeInstr |= instruction;     // Set the bits properly
  406.     }
  407.  
  408.     /** Returns the View's vertical resize instruction.
  409.       * @see #setVertResizeInstruction
  410.       */
  411.     public int vertResizeInstruction() {
  412.         return resizeInstr & VERT_MASK;
  413.     }
  414.  
  415.     /** Returns <B>true</B> if the View wants to automatically receive
  416.       * mouse dragged events when the user clicks and drags outside of its
  417.       * bounds.  Default implementation returns <b>false</b>.  Views
  418.       * that want to allow autoscrolling should override to return <b>true</b>.
  419.       */
  420.     public boolean wantsAutoscrollEvents() {
  421.         return false;
  422.     }
  423.  
  424.     /** Returns the object which should act as the destination of a
  425.       * DragSession.  Returns <b>null</b>.
  426.       * @see DragSession
  427.       * @see DragDestination
  428.       */
  429.     public DragDestination acceptsDrag(DragSession session, int x, int y) {
  430.         return null;
  431.     }
  432.  
  433.     /** Tells the IFC that this View should automatically resize
  434.       * and reposition its subviews when resized.
  435.       */
  436.     public void setAutoResizeSubviews(boolean flag) {
  437.         autoResizeSubviews = flag;
  438.     }
  439.  
  440.     /** Returns <b>true</b> if the View automatically resizes and repositions
  441.       * its subviews when it is resized.
  442.       * @see #setAutoResizeSubviews
  443.       */
  444.     public boolean doesAutoResizeSubviews() {
  445.         return autoResizeSubviews;
  446.     }
  447.  
  448.     /* size/bounds */
  449.  
  450.     /** Called by View's implementation of <b>setBounds()</b>. Subviews
  451.       * override this method to learn when they change position.
  452.       */
  453.     public void didMoveBy(int deltaX, int deltaY) {
  454.     }
  455.  
  456.     /** Called by <b>setBounds()</b> to resize a View's subviews. View
  457.       * subclasses requiring specialized resizing behavior should override
  458.       * this method.
  459.       */
  460.     public void didSizeBy(int deltaWidth, int deltaHeight) {
  461.         if (!autoResizeSubviews)
  462.             return;
  463.         layoutView(deltaWidth, deltaHeight);
  464.     }
  465.  
  466.     /** Convenience method for setting the bounds with a Rect. Equivalent
  467.       * to the code:
  468.       * <pre>
  469.       *     setBounds(rect.x, rect.y, rect.width, rect.height);
  470.       * </pre>
  471.       * @see #setBounds(int, int, int, int)
  472.       */
  473.     public void setBounds(Rect rect) {
  474.         setBounds(rect.x, rect.y, rect.width, rect.height);
  475.     }
  476.  
  477.     /** Primitive method for changing a View's bounds Rect. Sets the
  478.       * View's bounding rectangle and then calls <b>didMoveBy()</b>
  479.       * with the old origin, and <b>didSizeBy()</b> with the old size. It also
  480.       * adjusts the size of its drawingBuffer, if any, and notifies its
  481.       * superview if this View's size has changed.
  482.       * @see #bounds()
  483.       * @see #localBounds()
  484.       */
  485.     public void setBounds(int x, int y, int width, int height) {
  486.         // ALERT!...We shouldn't let the bounds change while we are drawing to
  487.         // the view...this might be hard because we don't have a focus stack.
  488.         // ALERT!...We should handle properly a negative width or height.
  489.         Rect    tmpRect;
  490.         int     dx, dy, dw, dh;
  491.         boolean didMove, didResize;
  492.  
  493.         dx = x - bounds.x;
  494.         dy = y - bounds.y;
  495.         dw = width - bounds.width;
  496.         dh = height - bounds.height;
  497.  
  498.         didMove = (dx != 0 || dy != 0);
  499.         didResize = (dw != 0 || dh != 0);
  500.  
  501.         if (!didMove && !didResize)
  502.             return;
  503.  
  504.         _setBounds(x, y, width, height);
  505.  
  506.         if (buffered && didResize) {
  507.             if (drawingBuffer != null) {
  508.                 drawingBuffer.flush();
  509.             }
  510.  
  511.             if (width > 0 && height > 0) {
  512.                 drawingBuffer = createBuffer();
  513.             } else {
  514.                 drawingBuffer = null;
  515.             }
  516.             drawingBufferValid = false;
  517.         }
  518.  
  519.         if (didMove) {
  520.             if (_superview != null) {
  521.                 _superview.subviewDidMove(this);
  522.             }
  523.             didMoveBy(dx, dy);
  524.         }
  525.  
  526.         if (didResize) {
  527.             if (_superview != null) {
  528.                 _superview.subviewDidResize(this);
  529.             }
  530.             didSizeBy(dw, dh);
  531.         }
  532.     }
  533.  
  534.     /** Convenience method to translate the View's origin by <B>deltaX</B>
  535.       * and <B>deltaY</B>. Calls <b>setBounds()</b>.
  536.       */
  537.     public void moveBy(int deltaX, int deltaY) {
  538.         setBounds(bounds.x + deltaX, bounds.y + deltaY,
  539.             bounds.width, bounds.height);
  540.     }
  541.  
  542.     /** Convenience method to translate the View's origin. Calls
  543.       * <b>setBounds()</b>.
  544.       */
  545.     public void moveTo(int x, int y) {
  546.         setBounds(x, y, bounds.width, bounds.height);
  547.     }
  548.  
  549.     /** Convenience method for changing the View's size.  Calls
  550.       * <b>setBounds()</b>.
  551.       */
  552.     public void sizeBy(int deltaWidth, int deltaHeight) {
  553.         setBounds(bounds.x, bounds.y, bounds.width +
  554.             deltaWidth, bounds.height + deltaHeight);
  555.     }
  556.  
  557.     /** Convenience method for setting the View's size.  Call
  558.       * <b>setBounds()</b>.
  559.       */
  560.     public void sizeTo(int width, int height) {
  561.         setBounds(bounds.x, bounds.y, width, height);
  562.     }
  563.  
  564.     /** Convenience method for setting the View's minimum size to
  565.       * (<B>width</B>, <B>height</B>).  This is the size that will be
  566.       * returned from the <b>minSize()</b> method.  Normally, <b>minSize()</b>
  567.       * computes a View subclass' minimum based on current conditions.  Setting
  568.       * a minimum size of (-1, -1) erases the previous minimum size set.
  569.       * @see #minSize
  570.       */
  571.     public void setMinSize(int width, int height) {
  572.         if (width == -1 || height == -1) {
  573.             _minSize = null;
  574.         } else {
  575.             _minSize = new Size(width, height);
  576.         }
  577.     }
  578.  
  579.     /** Returns the View's minimum size. If the minimum size has not been
  580.       * set, returns a Size instance with zero width and height.
  581.       * @see #setMinSize
  582.       */
  583.     public Size minSize() {
  584.         if (_minSize != null) {
  585.             return new Size(_minSize);
  586.         }
  587.  
  588.         return new Size();
  589.     }
  590.  
  591.     /** Resizes the View to the minimum size needed to display its contents.
  592.       * Calls the <B>minSize()</B> method to get the View's minimum size
  593.       * information.
  594.       * @see #minSize
  595.       */
  596.     public void sizeToMinSize() {
  597.         Size minSize = minSize();
  598.         sizeTo(minSize.width, minSize.height);
  599.     }
  600.  
  601.  
  602.  
  603. /* size change notification methods */
  604.  
  605.     /** Notifies a View that one of its subviews has changed size. This
  606.       * information is important to ScrollViews and other View subclasses
  607.       * that need to know if a descendant has changed size. The default
  608.       * implementation simply passes the notification up to the View's
  609.       * superview.
  610.       */
  611.     public void subviewDidResize(View aSubview) {
  612.         if (_superview != null) {
  613.             _superview.subviewDidResize(aSubview);
  614.         }
  615.     }
  616.  
  617.     /** Notifies a View that one of its subviews has moved. This
  618.       * information is important to ScrollViews and other View subclasses
  619.       * that need to know if a descendant has moved. The default
  620.       * implementation simply passes the notification up to the View's
  621.       * superview.
  622.       */
  623.     public void subviewDidMove(View aSubview) {
  624.         if (_superview != null) {
  625.             _superview.subviewDidMove(aSubview);
  626.         }
  627.     }
  628.  
  629.     /* view hierarchy */
  630.  
  631.     /** Sets the View's superview. You never call this method, but you might
  632.       * override it to perform some action when the superview changes.
  633.       * @see #addSubview
  634.       * @see #removeFromSuperview
  635.       */
  636.     private void setSuperview(View aView) {
  637.         RootView        rView;
  638.  
  639.         _superview = aView;
  640.         ancestorWasAddedToViewHierarchy(aView);
  641.  
  642.         rView = rootView();
  643.         if (rView != null) {
  644.             rView.updateCursorLater();
  645.             rView.viewHierarchyChanged();
  646.         }
  647.     }
  648.  
  649.     /** Adds <B>aView</B> to the Application's View hierarchy, as a subview
  650.       * of this View.
  651.       * @see #removeFromSuperview
  652.       * @see #ancestorWasAddedToViewHierarchy
  653.       */
  654.     public void addSubview(View aView) {
  655.         if (aView == null)
  656.             return;
  657.         invalidateKeyboardSelectionOrder();
  658.         if (subviews == null)
  659.             subviews = new Vector();
  660.         else if (subviews.contains(aView))
  661.             return;
  662.  
  663.         subviews.addElement(aView);
  664.         aView.setSuperview(this);
  665.         if(layoutManager != null)
  666.             layoutManager.addSubview(aView);
  667.  
  668.     }
  669.  
  670.     /** Called when the View or one of its ancestors has been added to the
  671.       * Application's View hierarchy.
  672.       * @see #addSubview
  673.       * @see #ancestorWillRemoveFromViewHierarchy
  674.       */
  675.     protected void ancestorWasAddedToViewHierarchy(View addedView) {
  676.         View    nextView;
  677.         int     i;
  678.  
  679.         if (buffered) {
  680.             setBuffered(true);
  681.         }
  682.  
  683.         if(needFocus)
  684.             setFocusedView();
  685.  
  686.         i = subviewCount();
  687.         while (i-- > 0) {
  688.             nextView = (View)subviews.elementAt(i);
  689.             nextView.ancestorWasAddedToViewHierarchy(addedView);
  690.         }
  691.     }
  692.  
  693.     protected void removeSubview(View aView) {
  694.         invalidateKeyboardSelectionOrder();
  695.         if (subviews != null)
  696.             subviews.removeElement(aView);
  697.         if(layoutManager != null)
  698.             layoutManager.removeSubview(aView);
  699.     }
  700.  
  701.     /** Removes the View from the Application's View hierarchy, setting its
  702.       * superview to becomes <b>null</b>.
  703.       * @see #addSubview
  704.       * @see #ancestorWillRemoveFromViewHierarchy
  705.       */
  706.     public void removeFromSuperview() {
  707.         RootView        rView;
  708.  
  709.         if (_superview != null) {
  710.             rView = rootView();
  711.             if (rView != null) {
  712.                 rView.updateCursorLater();
  713.             }
  714.  
  715.             ancestorWillRemoveFromViewHierarchy(this);
  716.  
  717.             _superview.removeSubview(this);
  718.  
  719.             _superview = null;
  720.  
  721.             if(rView != null)
  722.                 rView.viewHierarchyChanged();
  723.         }
  724.     }
  725.  
  726.     /** Called when the View or one of its ancestors has been removed from
  727.       * the Application's View hierarchy.
  728.       * You should call
  729.       *     super.ancestorWillRemoveFromViewHierarchy(removedView);
  730.       * before returning.
  731.       * @see #removeFromSuperview
  732.       * @see #ancestorWasAddedToViewHierarchy
  733.       */
  734.     protected void ancestorWillRemoveFromViewHierarchy(View removedView) {
  735.         RootView        rView;
  736.         View            nextView;
  737.         int             i;
  738.  
  739.         if (drawingBuffer != null) {
  740.             drawingBuffer.flush();
  741.             drawingBuffer = null;
  742.         }
  743.  
  744.         rView = rootView();
  745.         if (rView != null) {
  746.             if (rView.mouseView() == this) {
  747.                 rView.setMouseView(null);
  748.             }
  749.             if (rView._moveView == this) {
  750.                 rView._moveView = null;
  751.             }
  752.         }
  753.  
  754.         if (isDirty) {
  755.             setDirty(false);
  756.         }
  757.  
  758.         i = subviewCount();
  759.  
  760.         while (i-- > 0) {
  761.             nextView = (View)subviews.elementAt(i);
  762.             nextView.ancestorWillRemoveFromViewHierarchy(removedView);
  763.         }
  764.     }
  765.  
  766.     /* event handling */
  767.  
  768.  
  769.     /** Returns <B>true</B> if the View's <B>bounds</B> contains the point
  770.       * (<B>x</B>, <B>y</B>).
  771.       */
  772.     public boolean containsPoint(int x, int y) {
  773.         return Rect.contains(0, 0, width(), height(), x, y);
  774.     }
  775.  
  776.     /** Returns <B>true</B> if the View contains the point (<B>x</B>,
  777.       * <B>y</B>) within its visible rect.
  778.       * @see #computeVisibleRect
  779.       */
  780.     public boolean containsPointInVisibleRect(int x, int y) {
  781.         Rect            visibleRect;
  782.         boolean         containsPoint;
  783.  
  784.         visibleRect = Rect.newRect();
  785.         computeVisibleRect(visibleRect);
  786.  
  787.         containsPoint = visibleRect.contains(x, y);
  788.         Rect.returnRect(visibleRect);
  789.  
  790.         return containsPoint;
  791.     }
  792.  
  793.     /** Returns the smallest opaque View that completely contains <b>aRect</b>;
  794.       * <b>aRect</b> is in the callee's superview's coordinate system.  If
  795.       * <b>fromView</b> is <b>null</b>, it is assumed that the callee is the
  796.       * RootView.
  797.       */
  798.     View _viewForRect(Rect aRect, View fromView) {
  799.         View    nextView, viewForRect = null;
  800.         Rect    tmpRect;
  801.         int     i;
  802.  
  803.         if (aRect == null) {
  804.             return null;
  805.         }
  806.  
  807.         if (fromView != null) {
  808.             if (!bounds.contains(aRect)) {
  809.                 return null;
  810.             }
  811.  
  812.             /* convert to our coordinate system */
  813.             tmpRect = Rect.newRect();
  814.             fromView.convertRectToView(this, aRect, tmpRect);
  815.         } else {
  816.             /* already absolute */
  817.             tmpRect = Rect.newRect(aRect);
  818.         }
  819.  
  820.         i = subviewCount();
  821.         while (i-- > 0) {
  822.             nextView = (View)subviews.elementAt(i);
  823.             viewForRect = nextView._viewForRect(tmpRect, this);
  824.             if (viewForRect != null) {
  825.                 break;
  826.             }
  827.         }
  828.  
  829.         Rect.returnRect(tmpRect);
  830.  
  831.         if (viewForRect != null) {
  832.             return viewForRect;
  833.         } else if (isTransparent() && fromView != null) {
  834.             return null;
  835.         }
  836.  
  837.         return this;
  838.     }
  839.  
  840.     /** Returns the View containing the point (<B>x</B>, <B>y</B>). The
  841.       * View first checks its subviews to see if they contain the point,
  842.       * and if not, checks itself.
  843.       */
  844.     public View viewForMouse(int x, int y) {
  845.         View    hitView;
  846.         int     i;
  847.         Point   point = null, subPoint = null;
  848.  
  849.       /* have to make sure the point falls in our bounds first (we clip
  850.        * our subviews)
  851.        */
  852.         if (!containsPoint(x, y)) {
  853.             return null;
  854.         }
  855.  
  856.         i = subviewCount();
  857.         while (i-- > 0) {
  858.             View subView = (View)subviews.elementAt(i);
  859.  
  860.             if (subView instanceof InternalWindow) {
  861.                 continue;
  862.             }
  863.  
  864.             hitView = subView.viewForMouse(x - subView.bounds.x,
  865.                                            y - subView.bounds.y);
  866.             if (hitView != null) {
  867.                 return hitView;
  868.             }
  869.         }
  870.         return this;
  871.     }
  872.  
  873.     /** Returns the cursor that should appear when the mouse is over
  874.       * the point (<b>x</b>, <b>y</b>) in the View's coordinate system.  By
  875.       * default, this method returns ARROW_CURSOR.  Subclassers
  876.       * should override this method to implement custom cursor behavior.
  877.       */
  878.     public int cursorForPoint(int x, int y) {
  879.         return ARROW_CURSOR;
  880.     }
  881.  
  882.  
  883.  
  884.     /* events */
  885.  
  886.     /** Called when the user clicks the mouse in the View. You should override
  887.       * this method to return <b>true</b> if you want to receive subsequent
  888.       * <b>mouseDragged()</b> and <b>mouseUp()</b> messages.  By default, this
  889.       * method returns <b>false</b>.
  890.       * @see #mouseDragged
  891.       * @see #mouseUp
  892.       */
  893.     public boolean mouseDown(MouseEvent event) {
  894.         return false;
  895.     }
  896.  
  897.     /** Called when the user drags the mouse (moves it with the mouse button
  898.       * depressed) after having initially clicked in the View. The mouse
  899.       * down View will receive <B>mouseDragged()</B> messages until the
  900.       * user releases the mouse button, even if the user drags the mouse
  901.       * outside the mouse down View's bounds.
  902.       * @see #mouseDown
  903.       * @see #mouseUp
  904.       */
  905.     public void mouseDragged(MouseEvent event) {
  906.     }
  907.  
  908.     /** Called when the user releases the mouse button.
  909.       * @see #mouseDown
  910.       */
  911.     public void mouseUp(MouseEvent event) {
  912.     }
  913.  
  914.     /** Called when the mouse enters the View's bounds.
  915.       * @see #mouseMoved
  916.       * @see #mouseExited
  917.       */
  918.     public void mouseEntered(MouseEvent event) {
  919.     }
  920.  
  921.  
  922.     /** Called when the mouse moves within the View's bounds, after an initial
  923.       * <b>mouseEntered()</b> message.
  924.       * @see #mouseEntered
  925.       * @see #mouseMoved
  926.       */
  927.     public void mouseMoved(MouseEvent event) {
  928.     }
  929.  
  930.     /** Called when the mouse exits the View's bounds, after an initial
  931.       * <b>mouseEntered()</b> message.
  932.       * @see #mouseEntered
  933.       * @see #mouseMoved
  934.       */
  935.     public void mouseExited(MouseEvent event) {
  936.     }
  937.  
  938.     /** Called when the user presses a key. The View must register itself with
  939.       * the Application by calling its <b>setFocusedView()</b> method before it
  940.       * can receive key down and key up events.
  941.       * @see #setFocusedView
  942.       * @see #keyUp
  943.       */
  944.     public void keyDown(KeyEvent event) {
  945.         if (_superview != null) {
  946.             _superview.keyDown(event);
  947.         }
  948.     }
  949.  
  950.     /** Called when the user releases a key, after an initial key down message.
  951.       * @see #keyDown
  952.       */
  953.     public void keyUp(KeyEvent event) {
  954.         if (_superview != null) {
  955.             _superview.keyUp(event);
  956.         }
  957.     }
  958.  
  959.     /** Called when a unicode character has been generated after pressing one or more
  960.       * keys. Note: This method is called only when running with a 1.1 virtual machine
  961.       * and Application.application().handleExtendedKeyEvent returns true
  962.       * @see #keyUp
  963.       * @see #keyDown
  964.       */
  965.     public void keyTyped(KeyEvent event) {
  966.         if (_superview != null) {
  967.             _superview.keyTyped(event);
  968.         }
  969.     }
  970.  
  971.     /** Returns the View acting as this View's "scroll view," the View that
  972.       * service its <b>scrollRectToVisible()</b> requests.  A View acting
  973.       * as a "scroll view" should override this method and return itself.
  974.       * @see #scrollRectToVisible
  975.       */
  976.     View scrollingView() {
  977.         if (_superview != null) {
  978.             return _superview.scrollingView();
  979.         }
  980.  
  981.         return null;
  982.     }
  983.  
  984.     /** Forwards the <b>scrollRectToVisible()</b> message to the View's
  985.       * superview. Views that can service the request, such as a ScrollView,
  986.       * override this method and perform the scrolling.
  987.       *
  988.       * @see ScrollView
  989.       */
  990.     public void scrollRectToVisible(Rect aRect) {
  991.         if (_superview != null) {
  992.             _superview.scrollRectToVisible(
  993.                 convertRectToView(_superview, aRect));
  994.         }
  995.     }
  996.  
  997.  
  998.     /* drawing */
  999.  
  1000.     /** Disables drawing within the View and its subviews.  Call
  1001.       * <b>reenableDrawing()</b> to enable drawing.
  1002.       * <b>disableDrawing()</b>/<b>reenableDrawing()</b> pairs can be nested,
  1003.       * and must be balanced.
  1004.       * @see #reenableDrawing
  1005.       */
  1006.     public void disableDrawing() {
  1007.         drawingDisabled++;
  1008.     }
  1009.  
  1010.     /** Reenables drawing within the View and its subviews.
  1011.       * @see #disableDrawing
  1012.       */
  1013.     public void reenableDrawing() {
  1014.         drawingDisabled--;
  1015.         if (drawingDisabled < 0) {
  1016.             drawingDisabled = 0;
  1017.         }
  1018.     }
  1019.  
  1020.     /** Returns <B>true</B> if drawing is enabled within the View.
  1021.       * @see #disableDrawing
  1022.       */
  1023.     public boolean isDrawingEnabled() {
  1024.         return (drawingDisabled == 0);
  1025.     }
  1026.  
  1027.     /** Returns <B>true</B> if the View is a member of the Application's View
  1028.       * hierarchy.
  1029.       */
  1030.     public boolean isInViewHierarchy() {
  1031.         RootView rootView = rootView();
  1032.  
  1033.         return (rootView != null) && rootView.isVisible();
  1034.     }
  1035.  
  1036.     /** Returns the View's RootView, or <b>null</b> if the View isn't
  1037.       * currently in the View hierarchy.
  1038.       */
  1039.     public RootView rootView() {
  1040.         if (_superview == null)
  1041.             return null;
  1042.         else
  1043.             return _superview.rootView();
  1044.     }
  1045.  
  1046.     /** Returns <b>true</b> if the View is a member of the Application's View
  1047.       * hierarchy and drawing for the View is enabled.
  1048.       * @see #isDrawingEnabled
  1049.       */
  1050.     public boolean canDraw() {
  1051.         if (drawingDisabled > 0 || _superview == null) {
  1052.             return false;
  1053.         } else {
  1054.             return _superview.canDraw();
  1055.         }
  1056.     }
  1057.  
  1058.     /** Computes the View's "visible rect," the intersection
  1059.       * of the View's and all of its ancestors' bounding rectangles, placing
  1060.       * it in <b>visibleRect</b>.
  1061.       * @see Rect
  1062.       */
  1063.     public void computeVisibleRect(Rect visibleRect) {
  1064.  
  1065.         if (_superview == null) {
  1066.             visibleRect.setBounds(0, 0, width(), height());
  1067.         } else {
  1068.             _superview.computeVisibleRect(visibleRect);
  1069.             _superview.convertRectToView(this, visibleRect, visibleRect);
  1070.             visibleRect.intersectWith(0, 0, width(), height());
  1071.         }
  1072.     }
  1073.  
  1074.     /** Returns <B>true</B> if the View is transparent. A View that's
  1075.       * transparent has a <b>drawView()</B> method that doesn't paint all of
  1076.       * the bits within the View's bounds. By default, this method returns
  1077.       * <b>true</b>. Views which are totally opaque should override this method
  1078.       * to return <b>false</b> to improve drawing performance. It is always
  1079.       * safe to return <b>true</b>, but the View's superviews may be drawn
  1080.       * unnecessarily.
  1081.       */
  1082.     public boolean isTransparent() {
  1083.         return true;
  1084.     }
  1085.  
  1086.     /** Returns <B>true</B> if the View wants the IFC to
  1087.       * coalesce mouse move or drag events, instead of sending each
  1088.       * individual event to the View. Returns <B>true</B> unless overridden.
  1089.       * @see Window
  1090.       */
  1091.     public boolean wantsMouseEventCoalescing() {
  1092.         return true;
  1093.     }
  1094.  
  1095.     View opaqueAncestor() {
  1096.         if (isTransparent() && _superview != null) {
  1097.             return _superview.opaqueAncestor();
  1098.         }
  1099.  
  1100.         return this;
  1101.     }
  1102.  
  1103.     // All View code needs to be scrutinized to determine where View needs to
  1104.     // call addDirtyRect() and setDirty() on itself.  ALERT!
  1105.  
  1106.     /** Adds a rectangle to be drawn after the current Event is processed.
  1107.       * Calling <b>addDirtyRect(null)</b> dirties the entire View and is
  1108.       * equivalent to <b>setDirty(true)</b>.
  1109.       *
  1110.       * @see #setDirty
  1111.       * @see RootView#drawDirtyViews
  1112.       */
  1113.     public void addDirtyRect(Rect rect) {
  1114.         RootView rootView;
  1115.  
  1116.         if (rect == null) {
  1117.             setDirty(true);
  1118.             return;
  1119.         }
  1120.  
  1121.         // To keep from always storing a dirtyRect, (isDirty && dirtyRect ==
  1122.         // null) means that the whole View is dirty.  If we aren't in the View
  1123.         // hierarchy, then we never get dirty.
  1124.  
  1125.         if (isDirty) {
  1126.             if (dirtyRect != null)
  1127.                 dirtyRect.unionWith(rect);
  1128.         } else {
  1129.             rootView = rootView();
  1130.             if (rootView != null) {
  1131.                 dirtyRect = new Rect(rect);
  1132.                 rootView.markDirty(this);
  1133.                 isDirty = true;
  1134.             }
  1135.         }
  1136.     }
  1137.  
  1138.     /** Registers the View to be drawn after processing the current Event.
  1139.       * If <b>flag()</b> is <b>true</b>, the entire View is
  1140.       * marked as needing to be redrawn. If <b>flag()</b> is
  1141.       * <b>false</b>, then the View is marked as not needing to be drawn.
  1142.       * RootView's <b>drawDirtyViews()</b> method calls
  1143.       * <b>setDirty(false)</b> on each dirty View after it has been drawn.
  1144.       * @see RootView#drawDirtyViews
  1145.       */
  1146.     public void setDirty(boolean flag) {
  1147.         RootView rootView;
  1148.  
  1149.         // Only set the dirty bit if we are in the View hierarchy and can
  1150.         // register for a draw with our RootView.
  1151.  
  1152.         if (flag) {
  1153.             if (!isDirty) {
  1154.                 rootView = rootView();
  1155.                 if (rootView != null) {
  1156.                     rootView.markDirty(this);
  1157.                     isDirty = true;
  1158.                 }
  1159.             }
  1160.         } else {
  1161.             if (isDirty) {
  1162.                 rootView = rootView();
  1163.                 if (rootView != null) {
  1164.                     rootView.markClean(this);
  1165.                     isDirty = false;
  1166.                 }
  1167.             }
  1168.         }
  1169.  
  1170.         // No matter what, we don't need to keep a dirtyRect.  When isDirty
  1171.         // is true and dirtyRect is null, then the whole View is dirty.
  1172.  
  1173.         dirtyRect = null;
  1174.     }
  1175.  
  1176.     /** Returns <b>true</b> if the View will be redrawn after the current
  1177.       * Event has been processed.
  1178.       * @see #addDirtyRect
  1179.       * @see #setDirty
  1180.       */
  1181.     public boolean isDirty() {
  1182.         return isDirty;
  1183.     }
  1184.  
  1185.     /** Draws the View's contents. You rarely call this method directly,
  1186.       * but you will override it to implement any View subclass drawing.
  1187.       * The IFC sets the Graphics' clipping rectangle to the region requiring
  1188.       * a redraw, and the Graphics object's origin to correspond to the View's
  1189.       * coordinate system origin. This method draws only the View's contents,
  1190.       * not its subviews.  The default implementation does nothing.
  1191.       * @see #draw
  1192.       */
  1193.     public void drawView(Graphics g) {
  1194.     }
  1195.  
  1196.     /** Calls the <b>drawView()</b> method of each of the View's subviews.
  1197.       * You never call this method directly, but you can override it to
  1198.       * implement special drawing. For example, the following code draws a
  1199.       * blue rectangle around the View's perimeter, on top of any drawing its
  1200.       * subviews may have performed.
  1201.       * <pre>
  1202.       *     super.drawSubviews(g);
  1203.       *     g.setColor(Color.blue);
  1204.       *     g.drawRect(0, 0, width(),height());
  1205.       * </pre>
  1206.       * Placing the <b>drawRect()</b> within the View's <b>drawView()</b>
  1207.       * gives its subviews a chance to draw over the rect. The IFC sets the
  1208.       * passed-in Graphics' clipping rectangle to the region that requires a
  1209.       * redraw.
  1210.       */
  1211.     public void drawSubviews(Graphics g) {
  1212.         View            nextView;
  1213.         Rect            clipRect, subClipRect = null;
  1214.         int             count, i;
  1215.         boolean         canDraw;
  1216.  
  1217.         if (drawingDisabled > 0) {
  1218.             return;
  1219.         }
  1220.  
  1221.         clipRect = g.clipRect();
  1222.         count = subviewCount();
  1223.         for (i = 0; i < count; i++) {
  1224.             nextView = (View)subviews.elementAt(i);
  1225.  
  1226.             canDraw = nextView.isDrawingEnabled();
  1227.  
  1228.             if (subClipRect == null) {
  1229.                 subClipRect = Rect.newRect();
  1230.             }
  1231.  
  1232.             convertRectToView(nextView, clipRect, subClipRect);
  1233.             subClipRect.intersectWith(0, 0,
  1234.                                       nextView.bounds.width,
  1235.                                       nextView.bounds.height);
  1236.             if (canDraw && !subClipRect.isEmpty()) {
  1237.                 nextView._drawView(g, subClipRect, false);
  1238.             }
  1239.         }
  1240.  
  1241.         if (subClipRect != null) {
  1242.             Rect.returnRect(subClipRect);
  1243.         }
  1244.     }
  1245.  
  1246.     void _drawView(Graphics g, Rect drawRect, boolean isTopLevelView) {
  1247.         if (drawingDisabled > 0) {
  1248.             return;
  1249.         }
  1250.  
  1251.         g.pushState();
  1252.         g.setDebug(this);
  1253.  
  1254.         if (!isTopLevelView) {
  1255.             g.translate(bounds.x, bounds.y);
  1256.         }
  1257.  
  1258.         if (drawRect == null) {
  1259.             Rect clipRect = Rect.newRect(0, 0, width(), height());
  1260.  
  1261.             g.setClipRect(clipRect);
  1262.             Rect.returnRect(clipRect);
  1263.         } else {
  1264.             g.setClipRect(drawRect);
  1265.         }
  1266.  
  1267.         // draw from our drawing buffer (if we have one) *only if* we're the
  1268.         // View at the top-level being asked to draw, and we're not drawing
  1269.         // into a drawingBuffer; if we're a subview of a View that initiated
  1270.         // the _drawView() recursion, we never get a chance to draw to our
  1271.         // buffer before blitting it out, so we can't trust its current
  1272.         // contents
  1273.  
  1274.         if (drawingBuffer != null && isTopLevelView &&
  1275.             !g.isDrawingBuffer()) {
  1276.             drawingBuffer.drawAt(g, 0, 0);
  1277.         } else {
  1278.             drawView(g);
  1279.             drawSubviews(g);
  1280.         }
  1281.         g.popState();
  1282.     }
  1283.  
  1284.     void clipAndDrawView(Graphics g, Rect clipRect) {
  1285.         Vector       windowClipRectVector, clipVector, disunionRectVector,
  1286.                      newVector, newClipVector, tmpVector;
  1287.         Rect         currentRect, nextRect, newRect, nextClipRect,
  1288.                      windowClipRect, otherRect, ancestorVisibleRect;
  1289.         int          i, j, count;
  1290.         boolean      rectClipped;
  1291.  
  1292.         /* clip to our bounds if drawing into a buffer, otherwise clip to
  1293.          * visible rect
  1294.          */
  1295.         if (g.isDrawingBuffer()) {
  1296.             ancestorVisibleRect = Rect.newRect(0, 0, width(), height());
  1297.         } else {
  1298.             ancestorVisibleRect = Rect.newRect();
  1299.             computeVisibleRect(ancestorVisibleRect);
  1300.         }
  1301.  
  1302.         ancestorVisibleRect.intersectWith(clipRect);
  1303.         clipRect = ancestorVisibleRect;
  1304.  
  1305.         /* don't bother with windows if we're the bground view drawing our
  1306.          * complete contents, or we're drawing into a drawing buffer (in
  1307.          * that case, there are no windows to obscure us)
  1308.          */
  1309.         if (this == rootView() &&
  1310.             clipRect.x == 0 && clipRect.y == 0 &&
  1311.             clipRect.width == width() && clipRect.height == height() ||
  1312.             g.isDrawingBuffer()) {
  1313.             windowClipRectVector = null;
  1314.         } else {
  1315.             windowClipRectVector =
  1316.                   rootView().windowRects(convertRectToView(null, clipRect),
  1317.                                          window());
  1318.         }
  1319.  
  1320.         if (windowClipRectVector == null || windowClipRectVector.isEmpty()) {
  1321.             _drawView(g, clipRect, true);
  1322.  
  1323.             Rect.returnRect(clipRect);
  1324.         } else {
  1325.             disunionRectVector = VectorCache.newVector();
  1326.             clipVector = VectorCache.newVector();
  1327.  
  1328.             // We will be converting the other rects from the absolute system
  1329.             clipRect.x += absoluteX();
  1330.             clipRect.y += absoluteY();
  1331.  
  1332.             clipVector.addElement(clipRect);
  1333.             newClipVector = VectorCache.newVector();
  1334.  
  1335.             i = windowClipRectVector.count();
  1336.             while (i-- > 0) {
  1337.                 windowClipRect = (Rect)windowClipRectVector.elementAt(i);
  1338.  
  1339.                 j = clipVector.count();
  1340.                 while (j-- > 0) {
  1341.                     nextClipRect = (Rect)clipVector.elementAt(j);
  1342.                     nextClipRect.computeDisunionRects(windowClipRect,
  1343.                                                       disunionRectVector);
  1344.  
  1345.                     if (!disunionRectVector.isEmpty()) {
  1346.                         newClipVector.addElementsIfAbsent(disunionRectVector);
  1347.                         disunionRectVector.removeAllElements();
  1348.                     } else if (!windowClipRect.contains(nextClipRect)) {
  1349.                         newClipVector.addElement(nextClipRect);
  1350.                         clipVector.removeElement(nextClipRect);
  1351.                     }
  1352.                 }
  1353.  
  1354.                 tmpVector = clipVector;
  1355.                 clipVector = newClipVector;
  1356.                 newClipVector = tmpVector;
  1357.                 Rect.returnRects(newClipVector);
  1358.             }
  1359.             VectorCache.returnVector(disunionRectVector);
  1360.             VectorCache.returnVector(newClipVector);
  1361.  
  1362.             count = clipVector.count();
  1363.  
  1364.             /* do any clip rects mark the same area? */
  1365.             for (i = 0; i < count; i++) {
  1366.                 nextRect = (Rect)clipVector.elementAt(i);
  1367.  
  1368.                 j = count;
  1369.                 while (j-- > 0) {
  1370.                     otherRect = (Rect)clipVector.elementAt(j);
  1371.  
  1372.                     if (otherRect == nextRect) {
  1373.                         continue;
  1374.                     }
  1375.  
  1376.                     if (nextRect.contains(otherRect)) {
  1377.                         Rect.returnRect((Rect)clipVector.removeElementAt(j));
  1378.                         count--;
  1379.                         i = -1;
  1380.                         break;
  1381.                     }
  1382.                 }
  1383.             }
  1384.  
  1385.             i = clipVector.count();
  1386.  
  1387.             while (i-- > 0) {
  1388.                 clipRect = (Rect)clipVector.elementAt(i);
  1389.  
  1390.                 if (!clipRect.isEmpty()) {
  1391.                     // Convert to our coord system
  1392.                     clipRect.x -= absoluteX();
  1393.                     clipRect.y -= absoluteY();
  1394.                     _drawView(g, clipRect, true);
  1395.                 }
  1396.             }
  1397.             Rect.returnRects(clipVector);
  1398.             VectorCache.returnVector(clipVector);
  1399.         }
  1400.  
  1401.         Rect.returnRects(windowClipRectVector);
  1402.         VectorCache.returnVector(windowClipRectVector);
  1403.     }
  1404.  
  1405.     void _draw(Graphics g, Rect clipRect) {
  1406.         boolean         transparent;
  1407.  
  1408.         /* transparent views must make sure their superview has drawn; we do
  1409.          * this unless we have a DrawingBuffer and we're not drawing into it
  1410.          */
  1411.         transparent = (drawingBuffer != null && (!g.isDrawingBuffer())) ?
  1412.                                                     false : isTransparent();
  1413.  
  1414.         if (transparent && !(this instanceof InternalWindow)) {
  1415.             Rect ancestorClipRect = Rect.newRect();
  1416.             View opaqueAncestor = opaqueAncestor();
  1417.  
  1418.             convertRectToView(opaqueAncestor, clipRect, ancestorClipRect);
  1419.             g.pushState();
  1420.             g.translate(clipRect.x - ancestorClipRect.x,
  1421.                         clipRect.y - ancestorClipRect.y);
  1422.             opaqueAncestor.draw(g, ancestorClipRect);
  1423.             Rect.returnRect(ancestorClipRect);
  1424.             g.popState();
  1425.  
  1426.             return;
  1427.         }
  1428.  
  1429.         /* we're ready to go - make sure all buffers are valid */
  1430.         updateInvalidDrawingBuffers(clipRect);
  1431.  
  1432.         clipAndDrawView(g, clipRect);
  1433.     }
  1434.  
  1435.     /** Primitive method, instructing the View to draw the <B>clipRect</B>
  1436.       * portion of itself and its subviews to the Graphics <B>g</B>. If
  1437.       * <B>clipRect</B> is <B>null</B>, draws the entire View. If <B>g</B>
  1438.       * is <B>null</B>, uses the RootView's <B>graphics()</B>.
  1439.       * <B>draw()</B> sets the Graphics' clipping rectangle and ultimately
  1440.       * calls the View's and its subviews' <B>drawView()</B> methods. All
  1441.       * drawing occurs synchronously (that is, this method does not return
  1442.       * until the requested drawing has been performed).<p> You should
  1443.       * only call this form of <B>draw()</B> if you have to draw to a specific
  1444.       * Graphics. If not, use one of the more generic versions.
  1445.       */
  1446.     public void draw(Graphics g, Rect clipRect) {
  1447.         View            bufferView, nextView;
  1448.         Rect            tmpRect, absoluteClip;
  1449.         Point           point;
  1450.         int             count, i;
  1451.         boolean         canDraw;
  1452.  
  1453.         /* figure out what we're drawing */
  1454.         if (clipRect != null) {
  1455.             clipRect = Rect.newRect(clipRect);
  1456.             clipRect.intersectWith(0, 0, width(), height());
  1457.  
  1458.             if (clipRect.isEmpty()) {
  1459.                 Rect.returnRect(clipRect);
  1460.                 return;
  1461.             }
  1462.         } else {
  1463.             clipRect = Rect.newRect(0, 0, width(), height());
  1464.         }
  1465.  
  1466.         canDraw = canDraw();
  1467.  
  1468.         if (g == null || !g.isDrawingBuffer()) {
  1469. /* ALERT! - post1.0 - add the following line and change the if statement to:
  1470.             bufferView = ancestorWithDrawingBuffer();
  1471.  
  1472.             if (drawingBuffer == null || bufferView != this) {
  1473. */
  1474.             if (drawingBuffer == null) {
  1475.                 if (!canDraw) {
  1476.                     Rect.returnRect(clipRect);
  1477.                     return;
  1478.                 }
  1479.  
  1480.                 /* if an ancestor has a buffer, ask it to draw us */
  1481. /* ALERT! - post1.0 - comment out/remove the following line */
  1482.                 bufferView = ancestorWithDrawingBuffer();
  1483.                 if (bufferView != null && bufferView != this) {
  1484.                     tmpRect = Rect.newRect();
  1485.                     computeVisibleRect(tmpRect);
  1486.                     tmpRect.intersectWith(clipRect);
  1487.  
  1488.                     convertRectToView(bufferView, tmpRect, tmpRect);
  1489.                     bufferView.drawingBufferValid = false;
  1490.                     if (g == null) {
  1491.                         g = bufferView.createGraphics();
  1492.                         bufferView.draw(g, tmpRect);
  1493.                         g.dispose();
  1494.                         g = null;
  1495.                     } else {
  1496.                         point = new Point(0, 0);
  1497.                         convertPointToView(bufferView, point, point);
  1498.                         g.pushState();
  1499.                         try {
  1500.                             g.translate(-point.x, -point.y);
  1501.                             bufferView.draw(g, tmpRect);
  1502.                         } finally {
  1503.                             g.popState();
  1504.                         }
  1505.                     }
  1506.  
  1507.                     Rect.returnRect(tmpRect);
  1508.                     Rect.returnRect(clipRect);
  1509.  
  1510.                     return;
  1511.                 }
  1512.             } else {
  1513.                 /* if we're not drawing to a DrawingBuffer but we have one,
  1514.                  * we need to blit ourselves to our buffer before proceeding
  1515.                  */
  1516.  
  1517.                 if (!drawingBufferIsBitCache) {
  1518.                     updateDrawingBuffer(clipRect);
  1519.                 }
  1520.             }
  1521.  
  1522.             absoluteClip = convertRectToView(rootView(), clipRect);
  1523.             rootView().redrawTransparentWindows(absoluteClip, window());
  1524.         }
  1525.  
  1526.         /* time to really draw something */
  1527.         if ((g != null && g.isDrawingBuffer()) || canDraw) {
  1528.             if (g == null) {
  1529.                 g = createGraphics();
  1530.                 _draw(g, clipRect);
  1531.                 g.dispose();
  1532.                 g = null;
  1533.             } else {
  1534.                 _draw(g, clipRect);
  1535.             }
  1536.         }
  1537.  
  1538.         Rect.returnRect(clipRect);
  1539.     }
  1540.  
  1541.     /** Convenience method for drawing the <B>clipRect</B> portion of the
  1542.       * View. Equivalent to the code:
  1543.       * <pre>
  1544.       *     draw(createGraphics(), clipRect);
  1545.       * </pre>
  1546.       */
  1547.     public void draw(Rect clipRect) {
  1548.         if (isInViewHierarchy()) {
  1549.             draw(null, clipRect);
  1550.         }
  1551.     }
  1552.  
  1553.     /** Convenience method for drawing the entire View. Equivalent to
  1554.       * the code:
  1555.       * <pre>
  1556.       *     draw(createGraphics(), null);
  1557.       * </pre>
  1558.       */
  1559.     public void draw() {
  1560.         if (isInViewHierarchy()) {
  1561.             draw(null, null);
  1562.         }
  1563.     }
  1564.  
  1565.     /* drawing buffer support */
  1566.  
  1567.  
  1568.     /** Calling <b>setBuffered(true)</b> causes the View to allocate
  1569.       * an offscreen drawing buffer. The results of all drawing operations
  1570.       * performed within the View's <b>drawView()</b> method, and those of
  1571.       * its subviews, go first to the buffer and then to the screen, reducing
  1572.       * drawing flicker at the cost of speed and memory. In general,
  1573.       * reasonably flicker-free drawing can be achieved without drawing
  1574.       * buffers by careful attention to redrawing the minimum amount
  1575.       * necessary.
  1576.       */
  1577.     public void setBuffered(boolean flag) {
  1578.         buffered = flag;
  1579.  
  1580.         if (flag && drawingBuffer == null /*&&
  1581.             ancestorWithDrawingBuffer() == null*/) {
  1582.             if (bounds.width != 0 && bounds.height != 0) {
  1583.                 drawingBuffer = createBuffer();
  1584.             }
  1585.             drawingBufferValid = false;
  1586.         } else if (!flag && drawingBuffer != null) {
  1587.             drawingBuffer.flush();
  1588.             drawingBuffer = null;
  1589.         }
  1590.     }
  1591.  
  1592.     /** Returns <b>true</b> if the View has an offscreen drawing buffer.
  1593.       * @see #setBuffered
  1594.       */
  1595.     public boolean isBuffered() {
  1596.         return buffered;
  1597.     }
  1598.  
  1599.     /** Returns the View's offscreen drawing buffer, if any.
  1600.       * @see #setBuffered
  1601.       */
  1602.     public Bitmap drawingBuffer() {
  1603.         return drawingBuffer;
  1604.     }
  1605.  
  1606.     void updateDrawingBuffer(Rect updateRect) {
  1607.         Graphics bufferedGraphics;
  1608.  
  1609.         if (!updateRect.intersects(0, 0, width(), height())) {
  1610.             return;
  1611.         }
  1612.  
  1613.         if (drawingBuffer != null) {
  1614.             synchronized(drawingBuffer) {
  1615.                /* update the drawing buffer; we need to say that it's valid,
  1616.                 * before we actually do any drawing, otherwise if we're on
  1617.                 * the rootView, we'll get into a loop where the
  1618.                 * background tries to update our buffer before drawing itself
  1619.                 * and we ask the background to draw itself in order to
  1620.                 * validate our buffer
  1621.                 */
  1622.                 bufferedGraphics = Graphics.newGraphics(drawingBuffer);
  1623.                 drawingBufferValid = true;
  1624.  
  1625.                 bufferedGraphics.setDebugOptions(shouldDebugGraphics());
  1626.                 draw(bufferedGraphics, updateRect);
  1627.                 if (!canDraw()) {
  1628.                     drawingBufferValid = false;
  1629.                 }
  1630.                 bufferedGraphics.dispose();
  1631.                 bufferedGraphics = null;
  1632.             }
  1633.         }
  1634.     }
  1635.  
  1636.     void updateInvalidDrawingBuffers(Rect clipRect) {
  1637.         View            nextView;
  1638.         Rect            subClipRect = null;
  1639.         int             i;
  1640.  
  1641.         i = subviewCount();
  1642.         while (i-- > 0) {
  1643.             nextView = (View)subviews.elementAt(i);
  1644.  
  1645.             if (subClipRect == null) {
  1646.                 subClipRect = Rect.newRect();
  1647.             }
  1648.  
  1649.             convertRectToView(nextView, clipRect, subClipRect);
  1650.             if (!subClipRect.intersects(0, 0,
  1651.                                         nextView.width(),nextView.height())) {
  1652.                 continue;
  1653.             }
  1654.  
  1655.             if (nextView.drawingBuffer != null
  1656.                 && !nextView.drawingBufferValid) {
  1657.                 nextView.updateDrawingBuffer(subClipRect);
  1658.             }
  1659.  
  1660.             nextView.updateInvalidDrawingBuffers(subClipRect);
  1661.         }
  1662.  
  1663.         if (subClipRect != null) {
  1664.             Rect.returnRect(subClipRect);
  1665.         }
  1666.     }
  1667.  
  1668.     View ancestorWithDrawingBuffer() {
  1669.         if (drawingBuffer != null) {
  1670.             return this;
  1671.         } else if (_superview == null) {
  1672.             return null;
  1673.         }
  1674.  
  1675.         return _superview.ancestorWithDrawingBuffer();
  1676.  
  1677. /* ALERT! - post1.0 - use this new version:
  1678.         View    bufferedView = null;
  1679.  
  1680.         if (_superview != null) {
  1681.             bufferedView = _superview.ancestorWithDrawingBuffer();
  1682.         }
  1683.         if (bufferedView != null) {
  1684.             return bufferedView;
  1685.         } else if (drawingBuffer != null) {
  1686.             return this;
  1687.         }
  1688.  
  1689.         return null;
  1690. */
  1691.     }
  1692.  
  1693.     void _startFocus() {
  1694.         if(focusPaused) {
  1695.             focusPaused = false;
  1696.             resumeFocus();
  1697.         } else {
  1698.             startFocus();
  1699.         }
  1700.     }
  1701.  
  1702.     void _stopFocus() {
  1703.         focusPaused=false;
  1704.         stopFocus();
  1705.     }
  1706.  
  1707.     void _pauseFocus() {
  1708.         focusPaused=true;
  1709.         pauseFocus();
  1710.     }
  1711.  
  1712.     /** Tells the View that it has become the focus of KeyEvents.
  1713.       * @see #stopFocus
  1714.       */
  1715.     public void startFocus() {
  1716.     }
  1717.  
  1718.     /** Tells the View that it has ceased being the focus of KeyEvents.
  1719.       * @see #startFocus
  1720.       */
  1721.     public void stopFocus() {
  1722.     }
  1723.  
  1724.     /** Tells the View that it has temporarily ceased being the focus of
  1725.       * KeyEvents, such as when the user begins working with another
  1726.       * application.  The View will receive a <b>resumeFocus()</b> message when
  1727.       * it again regains focus.
  1728.       * @see #resumeFocus
  1729.       */
  1730.     public void pauseFocus() {
  1731.     }
  1732.  
  1733.     /** Tells the View that it has regained the KeyEvent focus.
  1734.       * @see #pauseFocus
  1735.       */
  1736.     public void resumeFocus() {
  1737.     }
  1738.  
  1739.     /** Tells a View that itself or one of its descendents wants to become the
  1740.       * focus of KeyEvents. By default, this method simply forwards the
  1741.       * message to its superview.  It will eventually reach the RootView
  1742.       * which will take appropriate action.  You should never call this method
  1743.       * directly on the RootView because there may be other Views between
  1744.       * a View and the RootView that want to know about focused View
  1745.       * change requests, such as an InternalWindow.
  1746.       */
  1747.     void setFocusedView(View view) {
  1748.         if (_superview != null )
  1749.             _superview.setFocusedView(view);
  1750.     }
  1751.  
  1752.     /** Tells a View that it should become the focus of KeyEvents.  The
  1753.       * View must be part of the View hierarchy in order to receive
  1754.       * KeyEvents.
  1755.       */
  1756.     public void setFocusedView() {
  1757.         if (_superview != null && (isInViewHierarchy() || window() != null)) {
  1758.             _superview.setFocusedView(this);
  1759.             needFocus = false;
  1760.         } else {
  1761.           needFocus = true;
  1762.         }
  1763.     }
  1764.  
  1765.  
  1766.     /* archiving */
  1767.  
  1768.     /** Describes the View class' information.
  1769.       * @see Codable#describeClassInfo
  1770.       */
  1771.     public void describeClassInfo(ClassInfo info) {
  1772.         info.addClass("netscape.application.View", 2);
  1773.         info.addField(BOUNDS_KEY, OBJECT_TYPE);
  1774.         info.addField(MINSIZE_KEY, OBJECT_TYPE);
  1775.         info.addField(SUBVIEWS_KEY, OBJECT_TYPE);
  1776.         info.addField(RESIZE_KEY, BYTE_TYPE);
  1777.         info.addField(DRAWINGDISABLED_KEY, INT_TYPE);
  1778.         info.addField(AUTORESIZE_KEY, BOOLEAN_TYPE);
  1779.         info.addField(BUFFERED_KEY, BOOLEAN_TYPE);
  1780.         info.addField(LAYOUTMANAGER_KEY, OBJECT_TYPE);
  1781.         info.addField(KEYBOARD_BINDINGS_KEY, OBJECT_TYPE);
  1782.     }
  1783.  
  1784.     /** Encodes the View instance.
  1785.       * @see Codable#decode
  1786.       */
  1787.     public void encode(Encoder encoder) throws CodingException {
  1788.         encoder.encodeObject(BOUNDS_KEY, bounds);
  1789.         encoder.encodeObject(MINSIZE_KEY, _minSize);
  1790.  
  1791.         if (subviewCount() == 0) {
  1792.             encoder.encodeObject(SUBVIEWS_KEY, null);
  1793.         } else {
  1794.             encoder.encodeObject(SUBVIEWS_KEY, subviews);
  1795.         }
  1796.  
  1797.         encoder.encodeByte(RESIZE_KEY, resizeInstr);
  1798.         encoder.encodeInt(DRAWINGDISABLED_KEY, drawingDisabled);
  1799.         encoder.encodeBoolean(AUTORESIZE_KEY, autoResizeSubviews);
  1800.         encoder.encodeBoolean(BUFFERED_KEY, buffered);
  1801.         encoder.encodeObject(LAYOUTMANAGER_KEY, layoutManager);
  1802.         encoder.encodeObject(KEYBOARD_BINDINGS_KEY,_keyboardBindings);
  1803.     }
  1804.  
  1805.     /** Decodes the View instance.
  1806.       * @see Codable#decode
  1807.       */
  1808.     public void decode(Decoder decoder) throws CodingException {
  1809.         int version = decoder.versionForClassName("netscape.application.View");
  1810.         Object          nextObject;
  1811.         boolean         flag;
  1812.  
  1813.         bounds = (Rect)decoder.decodeObject(BOUNDS_KEY);
  1814.         _minSize = (Size)decoder.decodeObject(MINSIZE_KEY);
  1815.         nextObject = decoder.decodeObject(SUBVIEWS_KEY);
  1816.         if (nextObject != null) {
  1817.             subviews = (Vector)nextObject;
  1818.         }
  1819.  
  1820.         resizeInstr = decoder.decodeByte(RESIZE_KEY);
  1821.         drawingDisabled = decoder.decodeInt(DRAWINGDISABLED_KEY);
  1822.  
  1823.         flag = decoder.decodeBoolean(AUTORESIZE_KEY);
  1824.         if (flag) {
  1825.             setAutoResizeSubviews(flag);
  1826.         }
  1827.         flag = decoder.decodeBoolean(BUFFERED_KEY);
  1828.         if (flag) {
  1829.             setBuffered(flag);
  1830.         }
  1831.  
  1832.         layoutManager = (LayoutManager)decoder.decodeObject(LAYOUTMANAGER_KEY);
  1833.  
  1834.         if(version >= 2) {
  1835.             _keyboardBindings = (Hashtable) decoder.decodeObject(KEYBOARD_BINDINGS_KEY);
  1836.         }
  1837.     }
  1838.  
  1839.     /** Finishes the View instance decoding.
  1840.       * @see Codable#finishDecoding
  1841.       */
  1842.     public void finishDecoding() throws CodingException {
  1843.         View    nextView;
  1844.         int     i;
  1845.  
  1846.         i = subviewCount();
  1847.         while (i-- > 0) {
  1848.             nextView = (View)subviews.elementAt(i);
  1849.             nextView.setSuperview(this);
  1850.             nextView._setBounds(nextView.bounds.x, nextView.bounds.y,
  1851.                                 nextView.bounds.width, nextView.bounds.height);
  1852.         }
  1853.         _setBounds(bounds.x, bounds.y, bounds.width, bounds.height);
  1854.     }
  1855.  
  1856.  
  1857.     /** Convenience method, returning the View's Application instance. */
  1858.     Application application() {
  1859.         return Application.application();
  1860.     }
  1861.  
  1862.     /** Converts the <B>x</B> and <B>y</B> to <B>otherView</B>'s
  1863.       * coordinate system, and stores the result in <B>destPoint</B>. If
  1864.       * <B>otherView</B> is <b>null</b>, <b>destPoint</b> will be in the
  1865.       * absolute coordinate system.
  1866.       */
  1867.     public void convertToView(View otherView, int x, int y, Point destPoint) {
  1868.         int destX = x, destY = y;
  1869.  
  1870.         if (_superview == otherView) {
  1871.             destX += bounds.x;
  1872.             destY += bounds.y;
  1873.         } else if (otherView != null && otherView._superview == this) {
  1874.             destX -= otherView.bounds.x;
  1875.             destY -= otherView.bounds.y;
  1876.         } else {
  1877.             View sView;
  1878.  
  1879.             for (sView = this;
  1880.                  sView._superview != null;
  1881.                  sView = sView._superview) {
  1882.                 destX += sView.bounds.x;
  1883.                 destY += sView.bounds.y;
  1884.             }
  1885.  
  1886.             if (otherView != null) {
  1887.                 View otherSView;
  1888.  
  1889.                 for (otherSView = otherView;
  1890.                         otherSView._superview != null;
  1891.                         otherSView = otherSView._superview) {
  1892.                     destX -= otherSView.bounds.x;
  1893.                     destY -= otherSView.bounds.y;
  1894.                 }
  1895.  
  1896.                 if (sView != otherSView) {
  1897.                     throw new InconsistencyException("Can't convert between " +
  1898.                         this + " and " + otherView + ", no common ancestor");
  1899.                 }
  1900.             }
  1901.         }
  1902.  
  1903.         destPoint.x = destX;
  1904.         destPoint.y = destY;
  1905.     }
  1906.  
  1907.     /** Converts the <B>x</B> and <B>y</B> to <B>otherView</B>'s
  1908.       * coordinate system, and returns the result. If
  1909.       * <B>otherView</B> is <b>null</b>, <b>destPoint</b> will be in the
  1910.       * absolute coordinate system.
  1911.       */
  1912.     public Point convertToView(View otherView, int x, int y) {
  1913.         Point point = new Point();
  1914.  
  1915.         convertToView(otherView, x, y, point);
  1916.         return point;
  1917.     }
  1918.  
  1919.     /** Converts the <B>sourceRect</B> to <B>otherView</B>'s coordinate
  1920.       * system, and stores the result in <B>destRect</B>. If <B>otherView</B>
  1921.       * is <b>null</b>, <B>destRect</B> will be in the absolute coordinate
  1922.       * system.
  1923.       */
  1924.     public void convertRectToView(View otherView,
  1925.                                   Rect sourceRect, Rect destRect) {
  1926.         Point destPoint = Point.newPoint();
  1927.  
  1928.         convertToView(otherView, sourceRect.x, sourceRect.y, destPoint);
  1929.         destRect.setBounds(destPoint.x, destPoint.y,
  1930.                            sourceRect.width, sourceRect.height);
  1931.         Point.returnPoint(destPoint);
  1932.     }
  1933.  
  1934.     /** Converts the <B>sourcePoint</B> to <B>otherView</B>'s coordinate
  1935.       * system, and stores the result in <B>destPoint</B>. If <B>otherView</B>
  1936.       * is <b>null</b>, <B>destPoint</B> will be in the absolute coordinate
  1937.       * system.
  1938.       */
  1939.     public void convertPointToView(View otherView,
  1940.                                    Point sourcePoint, Point destPoint) {
  1941.         convertToView(otherView, sourcePoint.x, sourcePoint.y, destPoint);
  1942.     }
  1943.  
  1944.     /** Returns the rectangle containing <B>sourceRect</B> converted
  1945.       * to <B>otherView</B>'s coordinate system. If <B>otherView</B> is
  1946.       * <b>null</b>, the returned Rect is in the absolute coordinate system.
  1947.       */
  1948.     public Rect convertRectToView(View otherView, Rect sourceRect) {
  1949.         Rect destRect = new Rect();
  1950.  
  1951.         convertRectToView(otherView, sourceRect, destRect);
  1952.         return destRect;
  1953.     }
  1954.  
  1955.     /** Returns a rectangle containing <B>srcPoint</B> converted
  1956.       * to <B>otherView</B>'s coordinate system. If <B>otherView</B> is
  1957.       * <b>null</b>, the returned Rect is in the absolute coordinate system.
  1958.       */
  1959.     public Point convertPointToView(View otherView, Point sourcePoint) {
  1960.         Point destPoint = new Point();
  1961.  
  1962.         convertPointToView(otherView, sourcePoint, destPoint);
  1963.         return destPoint;
  1964.     }
  1965.  
  1966.     /** Returns a MouseEvent similar to <b>sourceEvent</b> except that its x
  1967.       * and y members have been converted to <B>otherView</B>'s coordinate
  1968.       * system.  If <B>otherView</B> is <b>null</b>, the
  1969.       * returned MouseEvent is in the absolute coordinate system.
  1970.       */
  1971.     public MouseEvent convertEventToView(View otherView,
  1972.                                          MouseEvent sourceEvent) {
  1973.         Point destPoint = Point.newPoint();
  1974.         MouseEvent dstEvent = (MouseEvent)sourceEvent.clone();
  1975.  
  1976.         convertToView(otherView, sourceEvent.x, sourceEvent.y, destPoint);
  1977.         dstEvent.x = destPoint.x;
  1978.         dstEvent.y = destPoint.y;
  1979.  
  1980.         Point.returnPoint(destPoint);
  1981.         return dstEvent;
  1982.     }
  1983.  
  1984.     /** Enables or disables diagnostic information about every graphics
  1985.       * operation performed within the View or one of its subviews. The
  1986.       * value of <b>debug</b> determines how the View should display this
  1987.       * information:
  1988.       * <ul>
  1989.       * <li>DebugGraphics.LOG_OPTION - causes a text message to be printed.
  1990.       * <li>DebugGraphics.FLASH_OPTION - causes the drawing to flash several
  1991.       * times.
  1992.       * <li>DebugGraphics.BUFFERED_OPTION - creates an ExternalWindow that
  1993.       * displays the operations performed on the View's offscreen buffer.
  1994.       * </ul>
  1995.       * <b>debug</b> is bitwise OR'd into the current value.
  1996.       * DebugGraphics.NONE_OPTION disables debugging.
  1997.       * A value of 0 causes no changes to the debugging options.
  1998.       */
  1999.     public void setGraphicsDebugOptions(int debugOptions) {
  2000.         Graphics.setViewDebug(this, debugOptions);
  2001.     }
  2002.  
  2003.     /** Returns the state of graphics debugging.
  2004.       * @see #setGraphicsDebugOptions
  2005.       */
  2006.     public int graphicsDebugOptions() {
  2007.         return Graphics.viewDebug(this);
  2008.     }
  2009.  
  2010.     /** Returns <b>true</b> if debug information is enabled for this View
  2011.       * or one if its ancestors.
  2012.       */
  2013.     int shouldDebugGraphics() {
  2014.         return Graphics.shouldViewDebug(this);
  2015.     }
  2016.  
  2017.     int absoluteX() {
  2018.         int x = 0;
  2019.         View sView;
  2020.  
  2021.         for (sView = this; sView != null; sView = sView._superview) {
  2022.             x += sView.bounds.x;
  2023.         }
  2024.         return x;
  2025.     }
  2026.  
  2027.     int absoluteY() {
  2028.         int y = 0;
  2029.         View sView;
  2030.  
  2031.         for (sView = this; sView != null; sView = sView._superview) {
  2032.             y += sView.bounds.y;
  2033.         }
  2034.         return y;
  2035.     }
  2036.  
  2037.     /** Sets the View's LayoutManager, the object responsible for sizing
  2038.       * and positioning the View's subviews.
  2039.       */
  2040.     public void setLayoutManager(LayoutManager value)       {
  2041.         layoutManager = value;
  2042.     }
  2043.  
  2044.     /** Returns the View's LayoutManager.
  2045.       * @see #setLayoutManager
  2046.       */
  2047.     public LayoutManager layoutManager() {
  2048.         return layoutManager;
  2049.     }
  2050.  
  2051.     /** Sizes and positions the View's subviews.  By default, a View acts as
  2052.       * its own LayoutManager.
  2053.       */
  2054.     public void layoutView(int deltaWidth, int deltaHeight) {
  2055.         if(layoutManager == null)       {
  2056.             relativeLayoutView(deltaWidth, deltaHeight);
  2057.         } else {
  2058.             layoutManager.layoutView(this, deltaWidth, deltaHeight);
  2059.         }
  2060.     }
  2061.  
  2062.     private void relativeLayoutView(int deltaWidth, int deltaHeight) {
  2063.         int i;
  2064.         int x, y, w, h;
  2065.         View subview;
  2066.  
  2067.         i = subviewCount();
  2068.         while (i-- > 0) {
  2069.             subview = (View)subviews.elementAt(i);
  2070.  
  2071.             x = subview.bounds.x;
  2072.             y = subview.bounds.y;
  2073.             w = subview.bounds.width;
  2074.             h = subview.bounds.height;
  2075.  
  2076.             switch (subview.horizResizeInstruction()) {
  2077.                 case RIGHT_MARGIN_CAN_CHANGE:
  2078.                     break;
  2079.                 case LEFT_MARGIN_CAN_CHANGE:
  2080.                     x += deltaWidth;
  2081.                     break;
  2082.                 case WIDTH_CAN_CHANGE:
  2083.                     w += deltaWidth;
  2084. // ALERT - I don't think clipping to the min size is the right thing to do
  2085. //                    min = subview.minSize();
  2086. //                    if (w < min.width)
  2087. //                        w = min.width;
  2088.                     break;
  2089.                 case CENTER_HORIZ:
  2090.                     x = (bounds.width - subview.bounds.width) / 2 ;
  2091.                     break;
  2092.                 default:
  2093.                     throw new InconsistencyException("invalid horz resize instruction: " + subview.horizResizeInstruction());
  2094.             }
  2095.  
  2096.             switch (subview.vertResizeInstruction()) {
  2097.                 case BOTTOM_MARGIN_CAN_CHANGE:
  2098.                     break;
  2099.                 case TOP_MARGIN_CAN_CHANGE:
  2100.                     y += deltaHeight;
  2101.                     break;
  2102.                 case HEIGHT_CAN_CHANGE:
  2103.                     h += deltaHeight;
  2104. // ALERT - ditto
  2105. //                    if (min == null)
  2106. //                        min = subview.minSize();
  2107. //                    if (h < min.height)
  2108. //                        h = min.height;
  2109.                     break;
  2110.                 case CENTER_VERT:
  2111.                     y = (bounds.height - subview.bounds.height) / 2 ;
  2112.                     break;
  2113.                 default:
  2114.                     throw new InconsistencyException("invalid vert resize instruction: " + subview.vertResizeInstruction());
  2115.             }
  2116.  
  2117.             subview.setBounds(x, y, w, h);
  2118.         }
  2119.     }
  2120.  
  2121.     /** Returns the rectangle (0, 0, <b>width()</b>, <b>height()</b>).
  2122.       * @see #bounds()
  2123.       */
  2124.     public Rect localBounds() {
  2125.         return new Rect(0, 0, bounds.width, bounds.height);
  2126.     }
  2127.  
  2128.     /** Creates a Graphics object for the View.  The caller must call
  2129.       * <b>dispose()</b> on this Graphics to free its resources.  Subclasses
  2130.       * of View can override this method to return custom subclasses of
  2131.       * Graphics.<p>
  2132.       * This method throws an exception if the View is not in the View
  2133.       * hierarchy.
  2134.       * @see Graphics#dispose()
  2135.       */
  2136.     public Graphics createGraphics() {
  2137.         return Graphics.newGraphics(this);
  2138.     }
  2139.  
  2140.     /** Creates a Bitmap for the View to use as a drawing buffer.  View
  2141.       * subclasses can override this method to return custom subclasses of
  2142.       * Bitmap.
  2143.       */
  2144.     protected Bitmap createBuffer() {
  2145.         return new Bitmap(width(), height());
  2146.     }
  2147.  
  2148.     /** Returns the View's string representation. */
  2149.     public String toString() {
  2150.         return super.toString() + bounds.toString();
  2151.     }
  2152.  
  2153.     /** Keyboard UI support **/
  2154.  
  2155.     /** Return whether this view can become the selected view
  2156.       * when the user is moving from view to views with the keyboard
  2157.       * The default implementation returns false.
  2158.       *
  2159.       */
  2160.     public boolean canBecomeSelectedView() {
  2161.         return false;
  2162.     }
  2163.  
  2164.     /** Return whether this view hides its subviews from the keyboard ui
  2165.       * main system The default implementation returns false. Override this
  2166.       * method and return true if your view provides a different keyboard
  2167.       * UI strategy for its subviews.
  2168.       *
  2169.       */
  2170.     public boolean hidesSubviewsFromKeyboard() {
  2171.         return false;
  2172.     }
  2173.  
  2174.     /** Return the View that should become selected when the user
  2175.       * press the tab key. If the result is null, the keyboard UI
  2176.       * system will select the next available view.
  2177.       * The default implementation returns null.
  2178.       *
  2179.       */
  2180.     public View nextSelectableView() {
  2181.         return null;
  2182.     }
  2183.  
  2184.     /** Return the View that should become selected when the user
  2185.       * press the backtab key. If the result is null, the keyboard UI
  2186.       * system will select the next available view.
  2187.       * The default implementation returns null.
  2188.       *
  2189.       */
  2190.     public View previousSelectableView() {
  2191.         return null;
  2192.     }
  2193.  
  2194.     /** You should call this method if the result of nextSelectableView() or
  2195.       * previousSelectableView() changes.
  2196.       *
  2197.       */
  2198.    public void invalidateKeyboardSelectionOrder() {
  2199.        kbdOrder = null;
  2200.    }
  2201.  
  2202.     /** Inform the view that it is about to become the selected view
  2203.       * The default implementation requests RootView to display the
  2204.       * keyboard arrow.
  2205.       *
  2206.       */
  2207.     public void willBecomeSelected() {
  2208.         wantsKeyboardArrow = true;
  2209.     }
  2210.  
  2211.     /** Inform the view that it will no longer be the selected view
  2212.       * The default implementation requests RootView to hide the
  2213.       * keyboard arrow.
  2214.       */
  2215.     public void willBecomeUnselected() {
  2216.         wantsKeyboardArrow = false;
  2217.     }
  2218.  
  2219.     /** Inform the keyboard UI system that the receiving view should
  2220.       * receive the command <b>aCommand</b> with data <b>cmdData</b>
  2221.       * when the key <b>aKey</b> is pressed with the modifier <b>modifier</b>.
  2222.       * <b>when</b> can be View.WHEN_SELECTED, View.WHEN_IN_MAIN_WINDOW or
  2223.       * View.ALWAYS If <b>aCommand</b> is null, this method removes the
  2224.       * binding.  <b>aKey</b> can be one of the constants defined into the
  2225.       * KeyEvent class
  2226.       * @see KeyEvent
  2227.       *
  2228.       */
  2229.     public void setCommandForKey(String aCommand,Object cmdData,
  2230.                                  int key,int modifiers,int when) {
  2231.         KeyStroke keyStroke = new KeyStroke(key,modifiers);
  2232.         if(_keyboardBindings == null)
  2233.             _keyboardBindings = new Hashtable();
  2234.  
  2235.         if(aCommand == null)
  2236.             _keyboardBindings.remove(keyStroke);
  2237.         else {
  2238.             Hashtable data;
  2239.  
  2240.             data = new Hashtable();
  2241.             data.put(KBD_COMMAND_KEY,aCommand);
  2242.             data.put(KBD_WHEN,"" + when);
  2243.             if(cmdData != null)
  2244.                 data.put(KBD_DATA_KEY,cmdData);
  2245.             _keyboardBindings.put(keyStroke,data);
  2246.         }
  2247.     }
  2248.  
  2249.     /** Convenience to add <b>aCommand</b> when the key <b>aKey</b> is pressed.
  2250.       * This method calls setCommandForKey() with cmdData set to the
  2251.       * receiver and modifiers set to null.
  2252.       *
  2253.       */
  2254.     public void setCommandForKey(String aCommand,int aKey,int when) {
  2255.         setCommandForKey(aCommand,this,aKey,KeyEvent.NO_MODIFIERS_MASK,when);
  2256.     }
  2257.  
  2258.     /** Convenience to remove a command associated with a key.
  2259.       *
  2260.       */
  2261.     public void removeCommandForKey(int aKey) {
  2262.         setCommandForKey(null,null,aKey,KeyEvent.NO_MODIFIERS_MASK,0);
  2263.     }
  2264.  
  2265.     /** Remove all the command for all the keys **/
  2266.     public void removeAllCommandsForKeys() {
  2267.         _keyboardBindings = null;
  2268.     }
  2269.  
  2270.     boolean hasKeyboardBindings() {
  2271.         if(_keyboardBindings != null && _keyboardBindings.count() > 0)
  2272.             return true;
  2273.         else
  2274.             return false;
  2275.     }
  2276.  
  2277.     boolean performCommandForKeyStroke(KeyStroke aKeyStroke,int condition) {
  2278.         if(!(this instanceof Target))
  2279.             return false;
  2280.  
  2281.         if(_keyboardBindings!=null) {
  2282.             Enumeration keys = _keyboardBindings.keys();
  2283.             KeyStroke ks;
  2284.  
  2285.             while(keys.hasMoreElements()){
  2286.                 ks = (KeyStroke) keys.nextElement();
  2287.                 if(ks.equals(aKeyStroke)) {
  2288.                     boolean sendCommand = false;
  2289.                     Hashtable data = (Hashtable)_keyboardBindings.get(ks);
  2290.                     String s = (String)data.get(KBD_WHEN);
  2291.                     int when = Integer.parseInt(s);
  2292.  
  2293.                     switch(when) {
  2294.                     case WHEN_SELECTED:
  2295.                         if(condition == WHEN_SELECTED)
  2296.                             sendCommand = true;
  2297.                         break;
  2298.                     case WHEN_IN_MAIN_WINDOW:
  2299.                         if(condition == WHEN_SELECTED || condition == WHEN_IN_MAIN_WINDOW)
  2300.                             sendCommand = true;
  2301.                         break;
  2302.                     case ALWAYS:
  2303.                         sendCommand = true;
  2304.                         break;
  2305.                     default:
  2306.                         throw new InconsistencyException("Wrong condition:" + when);
  2307.                     }
  2308.                     if(sendCommand) {
  2309.                         String command = (String)data.get(KBD_COMMAND_KEY);
  2310.                         ((Target)this).performCommand(command,data.get(KBD_DATA_KEY));
  2311.                         return true;
  2312.                     }
  2313.                 }
  2314.             }
  2315.         }
  2316.  
  2317.         return false;
  2318.     }
  2319.  
  2320.     /** Return the rect that should be used to show the keyboard UI
  2321.      *  arrow. The default implementation returns localBounds()
  2322.      */
  2323.     public Rect keyboardRect() {
  2324.         return localBounds();
  2325.     }
  2326.  
  2327.     /** Return the subview that is on the top left corner **/
  2328.     View _firstSubview(Vector subViews) {
  2329.         int  minX,minY;
  2330.         View minXView,minYView,view;
  2331.         int i,c;
  2332.  
  2333.         if(subViews.count() == 0)
  2334.             return null;
  2335.         minYView = (View)subViews.elementAt(0);
  2336.         minY = minYView.y();
  2337.         for(i=1,c=subViews.count();i<c;i++) {
  2338.             view = (View)subViews.elementAt(i);
  2339.             if(view.y() < minY) {
  2340.                 minYView = view;
  2341.                 minY = view.y();
  2342.             }
  2343.         }
  2344.  
  2345.         minXView = minYView;
  2346.         minX = minYView.x();
  2347.         for(i=0,c=subViews.count();i<c;i++) {
  2348.             view = (View)subViews.elementAt(i);
  2349.             if(view == minXView)
  2350.                 continue;
  2351.  
  2352.             if((int)Math.sqrt((double)((view.y() - minXView.y()) *
  2353.                                        (view.y() - minXView.y()))) <= 10) {
  2354.                 if(view.x() < minX) {
  2355.                     minXView = view;
  2356.                     minX = view.x();
  2357.                 }
  2358.             }
  2359.         }
  2360.  
  2361.         return minXView;
  2362.     }
  2363.  
  2364.  
  2365.    private void validateKeyboardOrder() {
  2366.        if(kbdOrder==null){
  2367.            int i,c;
  2368.            Vector  sv = new Vector();
  2369.            View v,nv;
  2370.  
  2371.            for(i=0,c=subviews.count();i<c;i++)
  2372.                sv.addElement(subviews.elementAt(i));
  2373.  
  2374.            kbdOrder = new Vector();
  2375.            while(sv.count() > 0) {
  2376.                v = _firstSubview(sv);
  2377.                kbdOrder.addElement(v);
  2378.                sv.removeElement(v);
  2379.                while((nv = v.nextSelectableView()) != null) {
  2380.                    if(sv.indexOfIdentical(nv) != -1) {
  2381.                        kbdOrder.addElement(nv);
  2382.                        sv.removeElement(nv);
  2383.                        v = nv;
  2384.                    } else
  2385.                        break;
  2386.                }
  2387.            }
  2388.        }
  2389.    }
  2390.  
  2391.     View firstSubview() {
  2392.         validateKeyboardOrder();
  2393.         if(kbdOrder.count() > 0)
  2394.             return (View)kbdOrder.elementAt(0);
  2395.         else
  2396.             return null;
  2397.     }
  2398.  
  2399.     View lastSubview() {
  2400.         validateKeyboardOrder();
  2401.         if(kbdOrder.count() > 0)
  2402.             return (View)kbdOrder.elementAt(kbdOrder.count() - 1);
  2403.         else
  2404.             return null;
  2405.     }
  2406.  
  2407.     View viewAfter(View anotherView) {
  2408.         int index;
  2409.         validateKeyboardOrder();
  2410.  
  2411.         index = kbdOrder.indexOfIdentical(anotherView);
  2412.         if(index != -1 && index < (kbdOrder.count()-1))
  2413.             return (View)kbdOrder.elementAt(index + 1);
  2414.         else
  2415.             return null;
  2416.     }
  2417.  
  2418.     View viewBefore(View anotherView) {
  2419.         int index;
  2420.         validateKeyboardOrder();
  2421.  
  2422.         index = kbdOrder.indexOfIdentical(anotherView);
  2423.         if(index > 0)
  2424.             return (View)kbdOrder.elementAt(index - 1);
  2425.         else
  2426.             return null;
  2427.     }
  2428.  
  2429.     boolean wantsKeyboardArrow() {
  2430.         return wantsKeyboardArrow;
  2431.     }
  2432.  
  2433.     /** This method will collect the dirtyRects from this view and it's children
  2434.       * and union them into <b>rect</b>.
  2435.       */
  2436.     void getDirtyRect(Rect rect) {
  2437.         if (isDirty() && dirtyRect == null) {
  2438.             if (rect.isEmpty()) {
  2439.                 rect.setBounds(bounds);
  2440.             } else {
  2441.                 rect.unionWith(bounds);
  2442.             }
  2443.         } else {
  2444.             int count;
  2445.  
  2446.             if (dirtyRect != null) {
  2447.                 if (rect.isEmpty()) {
  2448.                     rect.setBounds(dirtyRect.x + bounds.x, dirtyRect.y + bounds.y,
  2449.                                    dirtyRect.width, dirtyRect.height);
  2450.                 } else {
  2451.                     rect.unionWith(dirtyRect.x + bounds.x, dirtyRect.y + bounds.y,
  2452.                                    dirtyRect.width, dirtyRect.height);
  2453.                 }
  2454.             }
  2455.  
  2456.             count = subviewCount();
  2457.             if (count != 0) {
  2458.                 rect.moveBy(-bounds.x, -bounds.y);
  2459.                 while (count-- > 0) {
  2460.                     ((View)subviews.elementAt(count)).getDirtyRect(rect);
  2461.                 }
  2462.                 rect.moveBy(bounds.x, bounds.y);
  2463.             }
  2464.         }
  2465.     }
  2466.  
  2467. }
  2468.  
  2469.  
  2470.  
  2471.  
  2472.  
  2473.  
  2474.